#!/usr/bin/env node
const webpack = require('webpack')
const { spawn } = require('child_process')
const path = require('path')
const WebpackDevServer = require('webpack-dev-server')
const { Command } = require('commander')
const clientConfig = require('./config/webpack.config')
const rendererConfig = require('./config/webpack.renderer')

const program = new Command()
program.name('AppPackager')
program.description('这个工具可以帮助你快速构建')
program.option('-s, --start', '启动开发服务器，并且启动app')
// 初始化命令
program.action((args) => {
  const start = args.start
  if (start) {
    startDevServer(clientConfig, rendererConfig)
  } else {
    build(clientConfig)
    build(rendererConfig)
  }
})
program.parse()

/**
 * 显示webpack的构建错误
 * @param {Error} err 错误信息
 * @param {webpack.Stats | undefined} stats 消息输出
 */
function webpackShowError(err, stats){
  if (err || stats.hasErrors()) {
    console.log(
      err ||
        stats.toString({
          preset: 'errors-only',
          colors: true
        })
    )
  }
}

/**
 * 打包编译
 * @param {Object} config 配置项
 * @param {string} name 名称
 */
function build (config) {
  webpack(config, (err, stats) => webpackShowError(err,stats))
}

/**
 * 开启开发模式
 * @param {Object} clientConfig 客户端配置
 * @param {Object} rendererConfig  服务器端配置
 */
async function startDevServer (clientConfig, rendererConfig) {
  let clientCompiled = false
  const ccompiler = webpack(clientConfig)
  const rcompiler = webpack(rendererConfig)
  let runContext = null
  const server = new WebpackDevServer(
    {
      ...clientConfig.devServer,
      hot: true,
      static: ccompiler.outputPath,
      devMiddleware: {
        writeToDisk: true
      }
    },
    ccompiler
  )
  ccompiler.hooks.done.tap('WEBPACK_SETUP', () => {
    clientCompiled = true
    openInApp()
  })
  // 启动开发服务器
  server.startCallback((err) => {
    if (err) return console.error('[System] DevServer start error: ', err)
    console.log('[System] DevServer started successfully')
  })
  // 监听服务器端和客户端的修改启动app
  rcompiler.watch(
    {
      aggregateTimeout: 100
    },
    (err, stats) => {
      webpackShowError(err,stats)
      if (clientCompiled) {
        openInApp()
      }
    }
  )
  /**
   * 重新打开App窗口，如果已经打开则不处理
   * @returns
   */
  function openInApp () {
    if (runContext) return
    console.log('\n App Open!')
    runContext = spawn(
      process.platform === 'win32' ? 'npx.cmd' : 'npx',
      ['electron', path.resolve(rcompiler.outputPath, 'main.js')],
      {
        cwd: rcompiler.outputPath
      }
    )
    runContext.stdout.pipe(process.stdout)
    runContext.stderr.pipe(process.stderr)
    runContext.on('close', () => {
      runContext = null
      console.log('\n App Close!')
    })
    runContext.on('exit', () => {
      runContext = null
      console.log('\n App Exit!')
    })
    runContext.on('disconnect', () => {
      runContext = null
      console.log('\n App Disconnect!')
    })
  }
}
